/*
 * Clase que representa al usuario que interactuará con el programa, se crea una
 * nueva instancia para cada nuevo proecto o diseño que se valla a crear,
 * Contiene los métodos por medio de los cuales se efectúan las tareas
 * que el usuario quiere ejecutar en el progra y que comunican la 
 * parte lógica del programa con la interfaz del usuario, 
 * así que funciona como patrón de diseño FACADE.
 */
package fuente;

import estructuras.ANBNode;
import estructuras.SLL;
import estructuras.SLLNode;

/**
 * @author Alexandre
 * @author Rodrigo
 * @author Gabriel
 * @author Jeremy
 */

public class Usuario {
    
    private String _nombre;//Nombre del usuario o el nuevo diseño
    private String _descripcion;//Descripción breve del nuevo diseño creado
    private int _entradas;//Cantidad de entradas que se desea para el nuevo diseño
    private int _salidas;//Cantidad de salidas que se desea para el nuevo diseño
    private int _compuertasCreadas;//Nuemro de compuertas que ha sido creadas, para llevar un contador para adjuntarlo al nombre de la compuerta al crearla
    
    private SLL _listaArboles;//Almacena los árboles creados de acuerdo a la cantidad de salidas
    private SLL _listaCompuertas;//Almacena las compuertas lógicas creadas (Nodos de árbol) para no perder referencia a ellas antes de crear sus enlaces
    private SLL _listaEntradas;//Almacena las entradas del diseño(Nodos de árbol)

    
    /**
     * Constructor, Inicializa los atributos:
     * _nombre y _descripción como strings vacíos
     * _entradas en 1
     * _salidas en 1
     * _Compuertas creadas en 1 (para comenzar la numeración de las etiquetas en 1)
     * e instancia las nuevas listas simples.
     */
    public Usuario () {
        _nombre = "";
        _descripcion = "";
        _entradas = 1;
        _salidas = 1;
        _compuertasCreadas = 1;
        _listaArboles = new SLL();
        _listaCompuertas = new SLL();
        _listaEntradas = new SLL();
    }
    
    ////////////////////////////Getters y setters///////////////////////////////
    /**
     * Obtiene el nombre del diseño
     * @return Nombre del diseño
     */
    public String getNombre() {
        return _nombre;
    }

    /**
     * Establece el nombre del diseño
     * @param pNombre Nombre del diseño
     */
    public void setNombre(String pNombre) {
        this._nombre = pNombre;
    }

    /**
     * Obtiene la descripción del diseño hecha por el usuario al iniciar
     * el nuevo diseño
     * @return Descripción del diseño
     */
    public String getDescripcion() {
        return _descripcion;
    }

    /**
     * Establece la descripción del diseño hecha por el usuario
     * @param pDescripcion Descripción del diseño
     */
    public void setDescripcion(String pDescripcion) {
        this._descripcion = pDescripcion;
    }

    /**
     * Obtiene la cantidad de entradas del diseño definidas por el usuario
     * @return Cantidad de entradas del diseño
     */
    public int getEntradas() {
        return _entradas;
    }

    /**
     * Establece la cantidad de entradas que va a tener el diseño
     * @param pEntradas Cantidad de entradas
     */
    public void setEntradas(int pEntradas) {
        this._entradas = pEntradas;
    }

    /**
     * Obtiene la cantidad de salidas que va a tener el diseño
     * @return Cantidad de salidas
     */
    public int getSalidas() {
        return _salidas;
    }

    /**
     * Establece la cantidad de salidas que tiene el diseño
     * @param pSalidas Cantidad de salidas
     */
    public void setSalidas(int pSalidas) {
        this._salidas = pSalidas;
    }
    
    /**
     * Obtiene el contador que referencia la cantidad e compuertas que han sido creadas
     * @return cantidad de compuertas creadas
     */
    public int getCompuertasCreadas () {
        return _compuertasCreadas;
    }

    /**
     * Establece la cantidad de compuertas que han sido creadas
     * @param pCount Contador de la cantidad de compuertas creadas
     */
    public void setCompuertasCreadas (int pCount) {
        this._compuertasCreadas = pCount;
    }
    
    /**
     * Obtiene la lista de árboles que se han creado por el usuario, las raíces 
     * de esos árboles son las salidas del diseño lógico
     * @return Lista de árboles
     */
    public SLL getListaArboles() {
        return _listaArboles;
    }

    /**
     * Establece una lista nueva de árboles que representan la interconexión
     * del diseño lógico
     * @param pListaArboles Lista de árboles
     */
    public void setListaArboles(SLL pListaArboles) {
        this._listaArboles = pListaArboles;
    }

    /**
     * Obtiene la lista de compuertas lógicas creadas, cada nodo contiene
     * una compuerta lógica que se añade al crear una nueva en el editor
     * @return Lista de compuertas lógicas creadas por el usuario
     */
    public SLL getListaCompuertas() {
        return _listaCompuertas;
    }

    /**
     * Etablece una nueva lista de compuertas lógicas
     * @param pListaCompuertas Lista de compuertas creadas
     */
    public void setListaCompuertas(SLL pListaCompuertas) {
        this._listaCompuertas = pListaCompuertas;
    }

    /**
     * Obtiene la lista de entradas del diseño lógico, en la lista cada nodo
     * contendrá como elemento una entrada del diseño, la cual, tendrá
     * sólo una lista de padres, osea, hacia qué compuertas va dirigida esa
     * entrada, y además su nombre de entrada (En, donde n es el número de entrada)
     * @return Lista de entradas
     */
    public SLL getListaEntradas() {
        return _listaEntradas;
    }

    /**
     * Establece una lista nueva de entradas del diseño lógico, en la lista cada nodo
     * contendrá como elemento una entrada del diseño, la cual, tendrá
     * sólo una lista de padres, osea, hacia qué compuertas va dirigida esa
     * entrada, y además su nombre de entrada (En, donde n es el número de entrada)
     * @param pListaEntradas Lista de entradas
     */
    public void setListaEntradas(SLL pListaEntradas) {
        this._listaEntradas = pListaEntradas;
    }
    ////////////////////////////////////////////////////////////////////////////
    
    
    /**
     * Crea una nueva compuerta lógica (Nodo de árbol) y la añade a la lista respectiva
     * de compuertas creadas (_compuertasCreadas).
     * @param pNombreCompuerta Nombre de la compuerta para crear
     */
    public void crearCompuerta (String pNombreCompuerta) {
        _listaCompuertas.meterFinal(new ANBNode(pNombreCompuerta, _compuertasCreadas, true));
    }
    
    /**
     * Crea una conexión entre dos compuertas lógicas
     * @param pCompuertaFuente Nombre de la compuerta de la cual sale el dato
     * @param pCompuertaDestino Nombre de la compuerta hacia la cual va el dato
     * @param pSalida Dice si la pCompuertaDestino es un componente salida del diseño total, si es true crea un nuevo arbol y lo añade a _listaArboles
     */
    public void crearConexión (String pCompuertaFuente, String pCompuertaDestino, boolean pSalida) {
        ANBNode nF = null;
        ANBNode nD = null;
        for (SLLNode n = _listaCompuertas.getHead(); n != null; n = n.getNext()) {
            ANBNode nComp = (ANBNode) n.getElemento();
            if (nComp.getCompuertaGraf().equals(pCompuertaFuente)) {
                nF = nComp;
                break;
            }
        }
        
        if (nF == null) {
            System.out.println("No se encontro nodo fuente");
            return;
        }
        
        for (SLLNode n = _listaCompuertas.getHead(); n != null; n = n.getNext()) {
            ANBNode nComp = (ANBNode) n.getElemento();
            if (nComp.getCompuertaGraf().equals(pCompuertaDestino)) {
                nD = nComp;
                break;
            }
        }
        
        if (nD == null) {
            System.out.println("No se encontro nodo destino");
            return;
        }
        
        nF.setPadre(nD);
        nD.agregarHijo(nF);
        
        if (pSalida) {
            _listaArboles.meterFinal(nD);
        }
    }
    
    /**
     * Encuentra los nodos de árboles (ANBNode; compuertas lógicas) y crea una lista de ellos
     * a partir de una lista de sus nombres (Strings).
     * @param pListaNombresCompuertas Lista de nombres de compuertas para encontrar y almacenar en una lista simple
     * @return Lista simple de los nodos de árboles o compuertas lógicas encontradas
     */
    private SLL encontrarCompuertas (SLL pListaNombresCompuertas) {
        SLL listaCompuertasDeEntradas = new SLL();
        for (SLLNode nN = pListaNombresCompuertas.getHead(); nN != null; nN = nN.getNext()) {
            String nombre = (String) nN.getElemento();
            
            for (SLLNode nC = pListaNombresCompuertas.getHead(); nC != null; nC = nC.getNext()) {
                ANBNode nComp = (ANBNode) nC.getElemento();
                String nombreComp = nComp.getCompuertaGraf();
                
                if (nombreComp.equals(nombre)) 
                    listaCompuertasDeEntradas.meterFinal(nComp);
            }
        }
        return listaCompuertasDeEntradas;
    }
    
    /**
     * Crea una nueva entrada, en el arbol funcionan como nodos hojas
     * con una lista de padres.
     * @param pNombreEntrada Nombre de la entrada (In; donde n es el numero de entrada
     * que le corresponde).
     */
    public void crearEntrada (SLL pListaPadres) {
        SLL listaCompuertasPadres = encontrarCompuertas(pListaPadres);
        if (_entradas > 0) {
            ANBNode entrada = new ANBNode("I", _entradas, false);
            entrada.setHijos(listaCompuertasPadres);
            _entradas--;
            _listaEntradas.meterFinal(entrada);
        }
        
        else {
            System.out.println("Ya estan credas todas las entradas necesarias");
        }
    }
}
